package de.mhu.mandalaui.bind;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;

import de.mhus.lib.lang.Raw;

public class DataRow extends HashMap<String, Object>{

	public DataRow() {
	}
	
	public DataRow(Object ... values) {
		for (int i = 0; i < values.length; i+=2) {
			put(values[i].toString(), values[i+1]);
		}
	}

	public String toJSONString() {
		StringBuffer out = new StringBuffer();
		out.append("{");
		boolean first = true;
		for (Map.Entry<String, Object> entry : entrySet()) {
			if (!first) out.append(',');
			out.append(entry.getKey()).append(':').append(toJSONString(entry.getValue()));
			first = false;
		}
		out.append("}");
		return out.toString();
	}

	private String toJSONString(Object value) {
		if (value == null)
			return "null";
		if (value instanceof Number)
			return value.toString();
		if (value instanceof Raw)
			return value.toString();
		if (value instanceof String)
			return "'" + encode(value.toString()) + "'";
		if (value instanceof DataRow)
			return ((DataRow)value).toJSONString();
		if (value instanceof List) {
			StringBuffer out = new StringBuffer();
			out.append('[');
			boolean first = true;
			for (Object v : ((List<?>)value)) {
				if (!first) out.append(',');
				out.append(toJSONString(v));
				first = false;
			}
			out.append(']');
			return out.toString();
		}
			
		return "'" + encode(value.toString()) + "'";
	}

	private String encode(String value) {
		if (value.indexOf('\\') >= 0 )
			value = value.replaceAll("\\\\", "\\\\\\\\'");
		if (value.indexOf('\'') >= 0 )
			value = value.replaceAll("'", "\\\\'");
		return value;
	}

	public void fill(ObjectNode next) {
		for (Map.Entry<String, Object> entry : entrySet()) {
			Object value = entry.getValue();
			if (value == null)
				next.putNull(entry.getKey());
			else
			if (value instanceof Integer)
				next.put(entry.getKey(), (Integer)value );
			else
			if (value instanceof Double)
				next.put(entry.getKey(), (Double)value );
			else
			if (value instanceof Float)
				next.put(entry.getKey(), (Float)value );
			else
			if (value instanceof Long)
				next.put(entry.getKey(), (Long)value );
			else
			if (value instanceof BigDecimal)
				next.put(entry.getKey(), (BigDecimal)value );
			else
			if (value instanceof Date)
				next.put(entry.getKey(), ((Date)value).getTime() ); //TODO - timestamp or ISO time format ?
			else
			if (value instanceof DataRow) {
				// TODO search for cycles
				ObjectNode nextNext = next.putObject(entry.getKey());
				((DataRow)value).fill(nextNext);
			} else
			if (value instanceof List) {
				ArrayNode nextArray = next.putArray(entry.getKey());
				for (Object o  : (List<?>)value) {
					ObjectNode item = nextArray.addObject();
					if (o instanceof DataRow)
						((DataRow)o).fill(item);
					else
						new DataRow("value",o).fill(item);
				}
			} else
			if (value instanceof String)
				next.put(entry.getKey(), value.toString());
			else
				next.put(entry.getKey(), value.toString());
		}
	}

}
